package edu.ncet.desktop.server;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.google.gwt.user.server.rpc.RemoteServiceServlet;

import edu.ncet.desktop.client.ExamsService;
import edu.ncet.desktop.server.common.DBConnectionInfo;
import edu.ncet.desktop.server.common.DBHelper;
import edu.ncet.desktop.server.common.DateTimeHelper;
import edu.ncet.desktop.shared.AnswerSheetModel;
import edu.ncet.desktop.shared.CurrentExamResult;
import edu.ncet.desktop.shared.HistoryResultModel;
import edu.ncet.desktop.shared.QuestionModel;
import edu.ncet.desktop.shared.ResultModel;
import edu.ncet.desktop.shared.TypeModel;

public class ExamServiceImpl extends RemoteServiceServlet implements ExamsService
{
	public DBHelper dbHelper = new DBHelper();
	private static final long serialVersionUID = 1L;

	Integer quesNo = new Integer(0);
	String question = new String();
	String[] answers = new String[4];
	private int estimatedTime;

	private ArrayList<QuestionModel> availableQues;

	
	public List<QuestionModel> loadQuestionPaper(List<TypeModel> questionTypeModels, Integer totQues) {
		String questionTypeInQuery = getInStatement(questionTypeModels );
		
		List<QuestionModel> questionSheet = new ArrayList<QuestionModel>();
		availableQues = new ArrayList<QuestionModel>();
		
		try {
			ResultSet resultSet = dbHelper.query("select * from "+ DBConnectionInfo.Questions +" where typeNo in {0};", questionTypeInQuery);
			while(resultSet.next()){
				quesNo = resultSet.getInt("quesNo");
				question = resultSet.getString("question");
				answers[0] = resultSet.getString("ans1");
				answers[1] = resultSet.getString("ans2");
				answers[2] = resultSet.getString("ans3");
				answers[3] = resultSet.getString("ans4");
				estimatedTime = resultSet.getInt("estimatedTime");
				QuestionModel qm = new QuestionModel(quesNo, question, answers,estimatedTime);
				availableQues.add(qm);
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}

		for(int i = 0 ; i < totQues ; i++)
		{
			if(i >= availableQues.size())
				break;
			
			QuestionModel selectedQues = availableQues.get(i);
			questionSheet.add(selectedQues); // Random number logic will go here
		}
		
		return questionSheet;
	}

	private String getInStatement(List<TypeModel> questionTypeModels ) {
		
		String questionTypeInQuery = "("; 
		
		for(TypeModel typeModel : questionTypeModels ) {
			questionTypeInQuery += (Integer)typeModel.get("typeNo") + "," ;
		}
		
		questionTypeInQuery = questionTypeInQuery.substring(0, questionTypeInQuery.length()-1);
		questionTypeInQuery += ")";
		return questionTypeInQuery;
	}

	public ResultModel submitAnswerSheet(AnswerSheetModel model) {
		List<CurrentExamResult> resModels = new ArrayList<CurrentExamResult>();
		ResultModel resModel = new ResultModel();
		try {
			ResultSet resultSet = dbHelper.query("select quesNo , question, ans1, ans2, ans3, ans4,  qt.typeNo , qt.typeName, correctAns from "+DBConnectionInfo.Questions+" q, "+DBConnectionInfo.QuestionType+" qt where q.typeNo = qt.typeNo", new String());
			Map<Integer, String> answerSheet = model.getAnswerSheet();
			while(resultSet.next()){
				Integer quesNo = resultSet.getInt("quesNo");
				if(answerSheet.containsKey(quesNo)) {
					String question = resultSet.getString("question");
					String ans1 = resultSet.getString("ans1");
					String ans2 = resultSet.getString("ans2");
					String ans3 = resultSet.getString("ans3");
					String ans4 = resultSet.getString("ans4");
					String[] answers = new String[]{ans1,ans2,ans3,ans4};
					String typeName = resultSet.getString("typeName");
					String correctAns = resultSet.getString("correctAns");
					Integer typeNo = resultSet.getInt("typeNo");
					String writtenAns = answerSheet.get(quesNo);
					CurrentExamResult temp = new CurrentExamResult(quesNo,question,answers,typeName,correctAns,writtenAns);
					temp.setTypeNo(typeNo);
					resModels.add(temp);
				}
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}
		
		try {
			updateHistory(resModels);
			resModel = new ResultModel(resModels, getHistories());
		} catch (SQLException e) {
			e.printStackTrace();
		}
		return resModel;
	}
	
	public List<HistoryResultModel> getHistories() throws SQLException
	{
		List<HistoryResultModel> historyModels = new ArrayList<HistoryResultModel>();
		ResultSet res = dbHelper.query("select tes.typeNo , tes.totMarks, tes.gotMarks from "+DBConnectionInfo.TestResult+" tes, "+DBConnectionInfo.TestHistory+" teh where tes.testNo=teh.testNo and teh.usrId = {0}", DBConnectionInfo.USR_ID.toString());
		Map<Integer,Integer> typeTotMarks = new HashMap<Integer, Integer>();
		Map<Integer,Integer> typeGotMarks = new HashMap<Integer, Integer>();
		while(res.next())
		{
			if(typeTotMarks.containsKey(res.getInt("typeNo")))
			{
				typeTotMarks.put(res.getInt("typeNo"), typeTotMarks.get(res.getInt("typeNo")) + res.getInt("totMarks"));
				typeGotMarks.put(res.getInt("typeNo"), typeGotMarks.get(res.getInt("typeNo")) + res.getInt("gotMarks"));
			}
			else
			{
				typeTotMarks.put(res.getInt("typeNo"),0);
				typeGotMarks.put(res.getInt("typeNo"),0);
			}
		}
		
		for(Integer typeNo : typeTotMarks.keySet())
		{
			int totMarks = typeTotMarks.get(typeNo);
			int gotMarks = typeGotMarks.get(typeNo);
			int percentage = (int)((1-(float)( totMarks - gotMarks )/totMarks)*100);
			historyModels.add(new HistoryResultModel(typeNo,percentage));
		}
		
		return historyModels;
	}

	public List<TypeModel> getQuestionTypes(String dummy) {
		List<TypeModel> questionTypeList = new ArrayList<TypeModel>();
		
		try {
			ResultSet resultSet = dbHelper.query("select * from "+ DBConnectionInfo.QuestionType +"", new String());
			while(resultSet.next()){
				Integer typeNo = resultSet.getInt("typeNo");
				String typeName = resultSet.getString("typeName");
				questionTypeList.add(new TypeModel(typeNo,typeName));
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}
		return questionTypeList;
	}
	
	private void updateHistory(List<CurrentExamResult> resModels) throws SQLException 
	{
		Integer testNo = 0;  
		Integer userId = DBConnectionInfo.USR_ID;
		ResultSet resultSet = dbHelper.query("select max(testNo) as testNo from "+DBConnectionInfo.TestHistory +" where usrId = {0}", userId.toString());
		if(resultSet.next()) 
		{
			testNo = resultSet.getInt("testNo");
			testNo += 1;
		}
		String date = DateTimeHelper.getString(new Date());
		dbHelper.insertToDBUsingNumberArgs(DBConnectionInfo.TestHistory, userId.toString(), testNo.toString() , Integer.toString(0) , date);
		updateResultViseMarks(resModels , testNo);
	}

	private void updateResultViseMarks(List<CurrentExamResult> resModels , int testNo) throws SQLException {
		Map<Integer,ResultByType> resultQuestions = new HashMap<Integer, ResultByType>();
		for(CurrentExamResult resModel : resModels)
		{
			Integer type = resModel.getTypeNo();
			if(!resultQuestions.containsKey(type))
			{
				resultQuestions.put(type,new ResultByType());
			}
			if(resModel.getCorrectAns().equals(resModel.getWrittenAns()))
			{
				resultQuestions.get(type).correctMarks++;
			}
			else
			{
				resultQuestions.get(type).incorrectMarks++;
			}
		}
		storeMarksToDB(resultQuestions,testNo);
	}

	private void storeMarksToDB(Map<Integer, ResultByType> resultQuestions , Integer testNo) throws SQLException {
		int totalCorrectMarks = 0;
		int totalIncorrectMarks = 0;
		for(Integer typeNo : resultQuestions.keySet())
		{
			Integer correctMarks = resultQuestions.get(typeNo).correctMarks;
			Integer totalQuestions =  resultQuestions.get(typeNo).correctMarks + resultQuestions.get(typeNo).incorrectMarks;
			dbHelper.insertToDBUsingNumberArgs(DBConnectionInfo.TestResult , testNo.toString() , typeNo.toString() , totalQuestions.toString() , correctMarks.toString()  );
			totalCorrectMarks += correctMarks;
			totalQuestions += totalQuestions;
		}
		Integer percentage = (int)((float)totalCorrectMarks / (totalCorrectMarks + totalIncorrectMarks) * 100);
		dbHelper.updateQuery("update " +DBConnectionInfo.TestHistory+ " set percentage = " + percentage.toString() + " where testNo = " + testNo);
	}

}

class ResultByType
{
	public Integer correctMarks = 0;
	public Integer incorrectMarks = 0;
}
